package com.whfc.iot.mach.util;

import com.whfc.iot.mach.constant.MsgConst;
import com.whfc.iot.mach.codec.MachMsgDataCodec;
import com.whfc.iot.mach.codec.MachMsgDataCodecFactory;
import com.whfc.iot.mach.entity.MachMsg;
import com.whfc.iot.mach.entity.MachMsgFactory;
import com.whfc.iot.util.ByteUtil;
import com.whfc.iot.util.CheckSumUtil;
import io.netty.buffer.ByteBuf;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class MachMsgUtil {

    private static Logger logger = LoggerFactory.getLogger(MachMsgUtil.class);

    /**
     * 编码
     *
     * @param buf
     * @param msg
     */
    public static void encode(ByteBuf buf, MachMsg msg) {
        //消息头
        encodeHeader(buf, msg);

        //消息体
        MachMsgDataCodec msgDataCodec = MachMsgDataCodecFactory.getMsgDataCodec(msg.getCmd());
        if (msgDataCodec != null) {
            msgDataCodec.encode(buf, msg);
        }

        //校验值
        encodeCheck(buf, msg);
    }

    /**
     * 解码
     *
     * @param buf
     * @return
     */
    public static MachMsg decode(ByteBuf buf) {
        //消息头
        MachMsg msg = decodeHeader(buf);

        //消息体
        MachMsgDataCodec msgDataCodec = MachMsgDataCodecFactory.getMsgDataCodec(msg.getCmd());
        if (msgDataCodec != null) {
            msgDataCodec.decode(buf, msg);
        }

        //校验值
        decodeCheck(buf, msg);
        return msg;
    }

    /**
     * 消息头-解码
     *
     * @param buf
     */
    public static MachMsg decodeHeader(ByteBuf buf) {

        //包头-开始标记0x55AA
        int startFlag = buf.readUnsignedShort();
        if (MsgConst.START_FLAG != startFlag) {
            logger.error("错误的包开始标记,startFlag:{}", startFlag);
            return null;
        }

        //终端类型
        int deviceType = buf.readUnsignedByte();

        //硬件终端ID
        byte[] deviceIdBytes = new byte[3];
        buf.readBytes(deviceIdBytes);
        int deviceId = ByteUtil.low3ByteToInt(deviceIdBytes);

        //包序号
        int seq = buf.readUnsignedByte();

        //包长度(包含整个包的内容)
        int length = buf.readUnsignedShort();
        if (length < MsgConst.FIXED_LENGTH) {
            logger.error("包长度不符合要求,length:{}", length);
            return null;
        }

        //指令
        int cmd = buf.readUnsignedByte();

        MachMsg msg = MachMsgFactory.create(cmd);
        msg.setStartFlag(startFlag);
        msg.setDeviceType(deviceType);
        msg.setDeviceId(deviceId);
        msg.setSeq(seq);
        msg.setLength(length);
        msg.setCmd(cmd);
        return msg;
    }

    /**
     * 消息头-编码
     *
     * @param buf
     * @param msg
     */
    public static void encodeHeader(ByteBuf buf, MachMsg msg) {
        //包头
        buf.writeShort(msg.getStartFlag());

        //终端类型
        buf.writeByte(msg.getDeviceType());

        //终端ID
        buf.writeBytes(ByteUtil.extractLow3Byte(msg.getDeviceId()));

        //包序号
        buf.writeByte(msg.getSeq());

        //包长度
        buf.writeShort(msg.getTotalLength());

        //指令
        buf.writeByte(msg.getCmd());
    }

    /**
     * 校验值-解码
     *
     * @param buf
     * @param msg
     */
    public static void decodeCheck(ByteBuf buf, MachMsg msg) {
        //校验值
        int rcvCheckSum = buf.readUnsignedByte();
        int calCheckSum = CheckSumUtil.checkSum(buf, 2, msg.getTotalLength() - 3);
        boolean checkSuccess = (rcvCheckSum == calCheckSum);
        if (!checkSuccess) {
            logger.warn("消息校验值不正确,rcvCheckSum:{},calCheckSum:{}", rcvCheckSum, calCheckSum);
        }
        msg.setCheckSum(rcvCheckSum);
        msg.setCheckSuccess(checkSuccess);
    }

    /**
     * 校验值-编码
     *
     * @param buf
     * @param msg
     */
    public static void encodeCheck(ByteBuf buf, MachMsg msg) {
        //校验值
        int checkSum = CheckSumUtil.checkSum(buf, 2, msg.getTotalLength() - 3);
        buf.writeByte(checkSum);
    }
}
